package org.dromara.easytl.parser;

import org.dromara.easytl.exception.TemplateSyntaxException;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 词法分析器（Lexer）
 * 
 * <p>负责将模板源代码转换为 Token 流，支持三种模式：</p>
 * <ul>
 *   <li>文本模式：解析普通文本内容，识别表达式和语句块的开始</li>
 *   <li>表达式模式：解析 {} 或 {{}} 中的表达式</li>
 *   <li>语句块模式：解析 {% %} 中的语句</li>
 * </ul>
 * 
 * <p>支持的语法特性：</p>
 * <ul>
 *   <li>字符串字面量（单引号、双引号、字符串模板）</li>
 *   <li>数字字面量（整数、长整数、大整数、浮点数、科学计数法、高精度小数）</li>
 *   <li>正则表达式字面量（/pattern/flags）</li>
 *   <li>运算符（算术、比较、逻辑、空安全、Elvis、正则匹配、区间）</li>
 *   <li>关键字（if、for、switch、let、extends、import 等）</li>
 *   <li>语句块标记（{%、%}、{/%）</li>
 * </ul>
 *
 * @author EasyTL Team
 */
public class Lexer {

    /**
     * 词法分析器的工作模式
     */
    private enum Mode {
        /** 文本模式：解析普通文本 */
        TEXT,
        /** 表达式模式：解析 {} 或 {{}} 中的表达式 */
        EXPRESSION,
        /** 语句块模式：解析 {% %} 中的语句 */
        STATEMENT
    }

    // 关键字映射
    private static final Map<String, Integer> KEYWORDS = new HashMap<>();
    static {
        KEYWORDS.put("if", TokenType.IF);
        KEYWORDS.put("else", TokenType.ELSE);
        KEYWORDS.put("for", TokenType.FOR);
        KEYWORDS.put("in", TokenType.IN);
        KEYWORDS.put("switch", TokenType.SWITCH);
        KEYWORDS.put("case", TokenType.CASE);
        KEYWORDS.put("default", TokenType.DEFAULT);
        KEYWORDS.put("let", TokenType.LET);
        KEYWORDS.put("extends", TokenType.EXTENDS);
        KEYWORDS.put("import", TokenType.IMPORT);
        KEYWORDS.put("true", TokenType.TRUE);
        KEYWORDS.put("false", TokenType.FALSE);
        KEYWORDS.put("null", TokenType.NULL);
    }

    private final Source source;
    private Mode mode;
    private int braceDepth;  // 花括号深度（用于跟踪嵌套）
    private boolean doubleBrace; // 是否使用双花括号
    private boolean dollarBrace; // 是否使用美元符号表达式
    private boolean pendingLeftBrace; // 是否有待输出的 LEFT_BRACE token
    private Integer lastExpressionTokenType; // 表达式模式下上一个 Token 类型

    public Lexer(Source source) {
        this.source = source;
        this.mode = Mode.TEXT;
        this.braceDepth = 0;
        this.doubleBrace = false;
        this.dollarBrace = false;
        this.pendingLeftBrace = false;
        this.lastExpressionTokenType = null;
    }

    /**
     * 读取下一个 Token
     * 
     * <p>根据当前模式（TEXT/EXPRESSION/STATEMENT）调用相应的 Token 读取方法</p>
     * 
     * @return 下一个 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    public Token nextToken() throws IOException {
        if (mode == Mode.TEXT) {
            return nextTextToken();
        } else if (mode == Mode.EXPRESSION) {
            return nextExpressionToken();
        } else {
            return nextStatementToken();
        }
    }

    /**
     * 根据表达式上下文更新最近一次返回的 Token 类型
     */
    private Token wrapExpressionToken(Token token) {
        int type = token.getType();
        if (type == TokenType.SINGLE_BRACE_EXPR_END || 
            type == TokenType.DOUBLE_BRACE_EXPR_END ||
            type == TokenType.DOLLAR_BRACE_EXPR_END) {
            lastExpressionTokenType = null;
        } else {
            lastExpressionTokenType = type;
        }
        return token;
    }

    /**
     * 判断当前是否应将 / 解析为正则表达式起始
     */
    private boolean isRegexContext() {
        if (lastExpressionTokenType == null) {
            return true;
        }
        return !isValueLikeToken(lastExpressionTokenType);
    }

    private boolean isValueLikeToken(int type) {
        switch (type) {
            case TokenType.IDENTIFIER:
            case TokenType.STRING:
            case TokenType.TEMPLATE_STRING:
            case TokenType.NUMBER:
            case TokenType.LONG:
            case TokenType.BIG_INTEGER:
            case TokenType.BIG_DECIMAL:
            case TokenType.REGEX:
            case TokenType.TRUE:
            case TokenType.FALSE:
            case TokenType.NULL:
            case TokenType.RIGHT_PAREN:
            case TokenType.RIGHT_BRACKET:
            case TokenType.RIGHT_BRACE:
            case TokenType.SINGLE_BRACE_EXPR_END:
            case TokenType.DOUBLE_BRACE_EXPR_END:
            case TokenType.DOLLAR_BRACE_EXPR_END:
                return true;
            default:
                return false;
        }
    }

    /**
     * 获取当前行号
     * 
     * @return 行号（从 1 开始）
     */
    public int getLine() {
        return source.getLine();
    }

    /**
     * 获取当前列号
     * 
     * @return 列号（从 1 开始）
     */
    public int getColumn() {
        return source.getColumn();
    }

    /**
     * 获取当前位置
     * 
     * @return 字符位置（从 0 开始）
     */
    public int getPosition() {
        return source.getPosition();
    }

    /**
     * 读取文本模式的 Token
     * 
     * <p>在文本模式下，识别以下内容：</p>
     * <ul>
     *   <li>普通文本内容 → TEXT</li>
     *   <li>表达式开始标记 { 或 {{ → EXPR_BEGIN，切换到表达式模式</li>
     *   <li>语句块开始标记 {% → STMT_BEGIN，切换到语句块模式</li>
     *   <li>语句块结束标记 {/% → STMT_CLOSE</li>
     * </ul>
     * 
     * @return 文本 Token 或控制标记 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private Token nextTextToken() throws IOException {
        StringBuilder text = new StringBuilder();
        int startLine = source.getLine();
        int startColumn = source.getColumn();
        int startPosition = source.getPosition();

        while (true) {
            int ch = source.peek();
            if (ch == -1) {
                break;
            }

            // 检查是否是表达式开始 {、{{ 或 ${
            if (ch == '{') {
                int next = source.peek(1);
                if (next == '%') {
                    // 语句块开始 {%
                    if (text.length() > 0) {
                        return new Token(TokenType.TEXT, text.toString(), startLine, startColumn, startPosition);
                    }
                    source.read(); // 消费 {
                    source.read(); // 消费 %
                    mode = Mode.STATEMENT;
                    return new Token(TokenType.STMT_BEGIN, "{%", startLine, startColumn, startPosition);
                } else if (next == '/' && source.peek(2) == '%') {
                    // 语句块关闭 {/%
                    // 标准语句块结束标签格式：{/% 语句名称 }
                    if (text.length() > 0) {
                        return new Token(TokenType.TEXT, text.toString(), startLine, startColumn, startPosition);
                    }
                    source.read(); // {
                    source.read(); // /
                    source.read(); // %
                    mode = Mode.STATEMENT; // 切换到语句块模式，以便解析后续的语句名称和 }
                    return new Token(TokenType.STMT_CLOSE, "{/%", startLine, startColumn, startPosition);
                } else if (next == '{') {
                    // 双花括号 {{
                    if (text.length() > 0) {
                        return new Token(TokenType.TEXT, text.toString(), startLine, startColumn, startPosition);
                    }
                    source.read(); // 消费第一个 {
                    source.read(); // 消费第二个 {
                    mode = Mode.EXPRESSION;
                    doubleBrace = true;
                    dollarBrace = false;
                    
                    // 检查是否是哈希表字面量模式 {{key: value}}
                    // 如果 {{ 后面跟着 identifier:、string: 或 number:，则认为是哈希表字面量
                    // 此时需要将 {{ 拆分为 SINGLE_BRACE_EXPR_BEGIN({) 和 LEFT_BRACE({)
                    if (looksLikeHashLiteral()) {
                        braceDepth = 0;
                        pendingLeftBrace = true;
                        lastExpressionTokenType = null;
                        return new Token(TokenType.SINGLE_BRACE_EXPR_BEGIN, "{", startLine, startColumn, startPosition);
                    } else {
                        braceDepth = 0;
                        lastExpressionTokenType = null;
                        return new Token(TokenType.DOUBLE_BRACE_EXPR_BEGIN, "{{", startLine, startColumn, startPosition);
                    }
                } else if (isExpressionStart(next)) {
                    // 单花括号表达式 {
                    if (text.length() > 0) {
                        return new Token(TokenType.TEXT, text.toString(), startLine, startColumn, startPosition);
                    }
                    source.read(); // 消费 {
                    mode = Mode.EXPRESSION;
                    doubleBrace = false;
                    dollarBrace = false;
                    braceDepth = 1;
                    lastExpressionTokenType = null;
                    return new Token(TokenType.SINGLE_BRACE_EXPR_BEGIN, "{", startLine, startColumn, startPosition);
                }
            } else if (ch == '$') {
                // 检查是否是美元符号表达式 ${
                int next = source.peek(1);
                if (next == '{') {
                    // 美元符号表达式 ${
                    if (text.length() > 0) {
                        return new Token(TokenType.TEXT, text.toString(), startLine, startColumn, startPosition);
                    }
                    source.read(); // 消费 $
                    source.read(); // 消费 {
                    mode = Mode.EXPRESSION;
                    doubleBrace = false;
                    dollarBrace = true;
                    braceDepth = 1;
                    lastExpressionTokenType = null;
                    return new Token(TokenType.DOLLAR_BRACE_EXPR_BEGIN, "${", startLine, startColumn, startPosition);
                }
            }

            // 普通文本
            text.append((char) source.read());
        }

        if (text.length() > 0) {
            return new Token(TokenType.TEXT, text.toString(), startLine, startColumn, startPosition);
        }

        return new Token(TokenType.EOF, startLine, startColumn, startPosition);
    }

    /**
     * 判断字符是否可以作为表达式的开始
     * 
     * <p>用于区分单花括号 { 后面是否是表达式，避免与 JSON 等格式中的 { 混淆</p>
     * 
     * @param ch 待判断的字符
     * @return 如果字符可以作为表达式的开始则返回 true
     */
    private boolean isExpressionStart(int ch) {
        // 如果是引号、空格或标识符开始，需要进一步检查是否是 JSON 格式
        if (ch == '"' || ch == '\'' || Character.isWhitespace(ch) || Character.isJavaIdentifierStart(ch)) {
            return !looksLikeJson();
        }
        
        return Character.isDigit(ch) ||
               ch == '`' ||
               ch == '[' || ch == '(' ||
               ch == '-' || ch == '+' || ch == '!' ||
               ch == '/'; // 正则表达式
    }
    
    /**
     * 检查当前位置（{{ 之后）是否看起来像哈希表字面量
     * 
     * <p>哈希表字面量的特征：</p>
     * <ul>
     *   <li>{} - 空哈希表</li>
     *   <li>{key: value} - 标识符键</li>
     *   <li>{"key": value} - 字符串键</li>
     *   <li>{123: value} - 数字键</li>
     * </ul>
     * <p>注意：调用此方法时，source 的当前位置在 {{ 之后</p>
     * 
     * @return 如果看起来像哈希表字面量则返回 true
     */
    private boolean looksLikeHashLiteral() {
        try {
            source.mark();
            
            // 跳过空白字符
            while (true) {
                int ch = source.peek();
                if (ch == -1 || !Character.isWhitespace(ch)) {
                    break;
                }
                source.read();
            }
            
            int ch = source.peek();
            
            // 空哈希表 {}
            if (ch == '}') {
                source.reset();
                return true;
            }
            
            // 检查键：可以是字符串、标识符或数字
            boolean isKey = false;
            
            if (ch == '"' || ch == '\'') {
                // 字符串键
                int quoteChar = ch;
                source.read(); // 消费开始引号
                
                // 扫描到键字符串结束
                while (true) {
                    ch = source.peek();
                    if (ch == -1) {
                        source.reset();
                        return false;
                    }
                    
                    if (ch == quoteChar) {
                        source.read(); // 消费结束引号
                        isKey = true;
                        break;
                    }
                    
                    if (ch == '\\') {
                        source.read(); // 消费反斜杠
                        int next = source.peek();
                        if (next != -1) {
                            source.read(); // 消费转义字符
                        }
                    } else {
                        source.read();
                    }
                }
            } else if (Character.isJavaIdentifierStart(ch)) {
                // 标识符键
                source.read(); // 消费第一个字符
                while (true) {
                    ch = source.peek();
                    if (ch == -1 || !Character.isJavaIdentifierPart(ch)) {
                        break;
                    }
                    source.read();
                }
                isKey = true;
            } else if (Character.isDigit(ch) || ch == '-') {
                // 数字键
                source.read(); // 消费第一个字符
                while (true) {
                    ch = source.peek();
                    if (ch == -1 || !(Character.isDigit(ch) || ch == '.' || ch == 'e' || ch == 'E')) {
                        break;
                    }
                    source.read();
                }
                isKey = true;
            }
            
            if (!isKey) {
                source.reset();
                return false;
            }
            
            // 跳过空白字符
            while (true) {
                ch = source.peek();
                if (ch == -1 || !Character.isWhitespace(ch)) {
                    break;
                }
                source.read();
            }
            
            // 检查是否有冒号
            if (ch != ':') {
                source.reset();
                return false;
            }
            
            // 有 key: 格式，认为是哈希表字面量
            source.reset();
            return true;
            
        } catch (Exception e) {
            try {
                source.reset();
            } catch (Exception ignored) {
            }
            return false;
        }
    }

    /**
     * 检查 { 后面的内容是否看起来像 JSON 格式
     * 
     * <p>JSON 文本的特征：</p>
     * <ul>
     *   <li>{"key": value} - 字符串键且有冒号</li>
     *   <li>{key: value} - 标识符键且有冒号（JavaScript 对象字面量）</li>
     * </ul>
     * <p>只要检测到键后跟冒号的格式，就认为是 JSON/对象字面量文本</p>
     * <p>注意：调用此方法时，source 的当前位置在 { 字符前面</p>
     * 
     * @return 如果看起来像 JSON 文本则返回 true
     */
    private boolean looksLikeJson() {
        try {
            source.mark();
            
            // 跳过 { 字符
            int ch = source.read();
            if (ch != '{') {
                source.reset();
                return false;
            }
            
            // 跳过空白字符
            while (true) {
                ch = source.peek();
                if (ch == -1 || !Character.isWhitespace(ch)) {
                    break;
                }
                source.read();
            }
            
            // 检查键：可以是字符串（引号）或标识符
            boolean isStringKey = (ch == '"' || ch == '\'');
            
            if (isStringKey) {
                // 字符串键
                int quoteChar = ch;
                source.read(); // 消费开始引号
                
                // 扫描到键字符串结束
                while (true) {
                    ch = source.peek();
                    if (ch == -1) {
                        source.reset();
                        return false;
                    }
                    
                    if (ch == quoteChar) {
                        source.read(); // 消费结束引号
                        break;
                    }
                    
                    if (ch == '\\') {
                        source.read(); // 消费反斜杠
                        int next = source.peek();
                        if (next != -1) {
                            source.read(); // 消费转义字符
                        }
                    } else {
                        source.read();
                    }
                }
            } else if (Character.isJavaIdentifierStart(ch)) {
                // 标识符键
                source.read(); // 消费第一个字符
                while (true) {
                    ch = source.peek();
                    if (ch == -1 || !Character.isJavaIdentifierPart(ch)) {
                        break;
                    }
                    source.read();
                }
            } else {
                // 既不是字符串也不是标识符，不是 JSON
                source.reset();
                return false;
            }
            
            // 跳过空白字符
            while (true) {
                ch = source.peek();
                if (ch == -1 || !Character.isWhitespace(ch)) {
                    break;
                }
                source.read();
            }
            
            // 检查是否有冒号
            if (ch != ':') {
                source.reset();
                return false;
            }
            
            // 有 key: 格式，认为是 JSON/对象字面量文本
            source.reset();
            return true;
            
        } catch (Exception e) {
            try {
                source.reset();
            } catch (Exception ignored) {
            }
            return false;
        }
    }

    /**
     * 读取表达式模式的 Token
     * 
     * <p>在表达式模式下（{} 或 {{}} 内部），识别以下内容：</p>
     * <ul>
     *   <li>字符串字面量（单引号、双引号）</li>
     *   <li>字符串模板字面量（反引号）</li>
     *   <li>数字字面量（整数、长整数、大整数、浮点数、科学计数法）</li>
     *   <li>正则表达式字面量（/pattern/flags）</li>
     *   <li>标识符和关键字</li>
     *   <li>运算符和分隔符</li>
     *   <li>表达式结束标记 } 或 }} → EXPR_END 或 RIGHT_BRACE，切换回文本模式</li>
     * </ul>
     * 
     * @return 表达式内的 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private Token nextExpressionToken() throws IOException {
        // 如果有待输出的 LEFT_BRACE，先输出它
        if (pendingLeftBrace) {
            pendingLeftBrace = false;
            int line = source.getLine();
            int column = source.getColumn();
            int position = source.getPosition();
            braceDepth++;
            return wrapExpressionToken(new Token(TokenType.LEFT_BRACE, "{", line, column, position));
        }
        
        skipWhitespace();

        int ch = source.peek();
        if (ch == -1) {
            throw new TemplateSyntaxException("表达式未闭合", source.getLine(), source.getColumn());
        }

        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        // 检查表达式结束
        if (ch == '}') {
            if (dollarBrace) {
                // 美元符号表达式模式
                source.read(); // 消费 }
                braceDepth--;
                if (braceDepth == 0) {
                    mode = Mode.TEXT;
                    dollarBrace = false;
                    return wrapExpressionToken(new Token(TokenType.DOLLAR_BRACE_EXPR_END, "}", line, column, position));
                }
                return wrapExpressionToken(new Token(TokenType.RIGHT_BRACE, "}", line, column, position));
            } else if (doubleBrace) {
                // 双花括号模式
                if (braceDepth == 0) {
                    // braceDepth == 0，表示没有嵌套花括号，检查是否是 }} 表达式结束
                    int next = source.peek(1);
                    if (next == '}') {
                        // }} 作为整体的 DOUBLE_BRACE_EXPR_END
                        source.read(); // 消费第一个 }
                        source.read(); // 消费第二个 }
                        mode = Mode.TEXT;
                        doubleBrace = false;
                        return wrapExpressionToken(new Token(TokenType.DOUBLE_BRACE_EXPR_END, "}}", line, column, position));
                    } else {
                        // 只有一个 }，是单独的 DOUBLE_BRACE_EXPR_END
                        source.read(); // 消费 }
                        mode = Mode.TEXT;
                        doubleBrace = false;
                        return wrapExpressionToken(new Token(TokenType.SINGLE_BRACE_EXPR_END, "}", line, column, position));
                    }
                } else {
                    // braceDepth > 0，说明有嵌套的花括号（如哈希表字面量）
                    // 此时 } 是 RIGHT_BRACE
                    source.read(); // 消费 }
                    braceDepth--;
                    return wrapExpressionToken(new Token(TokenType.RIGHT_BRACE, "}", line, column, position));
                }
            } else {
                // 单花括号模式
                source.read(); // 消费 }
                braceDepth--;
                if (braceDepth == 0) {
                    mode = Mode.TEXT;
                    return wrapExpressionToken(new Token(TokenType.SINGLE_BRACE_EXPR_END, "}", line, column, position));
                }
                return wrapExpressionToken(new Token(TokenType.RIGHT_BRACE, "}", line, column, position));
            }
        }

        // 字符串字面量
        if (ch == '"' || ch == '\'') {
            return wrapExpressionToken(readStringLiteral());
        }

        // 字符串模板字面量
        if (ch == '`') {
            return wrapExpressionToken(readTemplateLiteral());
        }

        // 数字字面量
        if (Character.isDigit(ch) || (ch == '-' && Character.isDigit(source.peek(1)))) {
            return wrapExpressionToken(readNumberLiteral());
        }

        // 正则表达式（需要在特定上下文中识别）
        if (ch == '/' && isRegexContext()) {
            Token regex = tryReadRegex();
            if (regex != null) {
                return wrapExpressionToken(regex);
            }
        }

        // 标识符或关键字
        if (Character.isJavaIdentifierStart(ch)) {
            return wrapExpressionToken(readIdentifierOrKeyword());
        }

        // 运算符和分隔符
        return wrapExpressionToken(readOperatorOrDelimiter());
    }

    /**
     * 读取语句块模式的 Token
     * 
     * <p>在语句块模式下（{% %} 内部），识别以下内容：</p>
     * <ul>
     *   <li>标识符和关键字（if、for、let、extends、import 等）</li>
     *   <li>字符串字面量（用于 extends 路径、import 类名等）</li>
     *   <li>数字字面量</li>
     *   <li>运算符和分隔符</li>
     *   <li>语句块结束标记 %} → STMT_END，切换回文本模式</li>
     *   <li>标准语句块开始标签结束 } → RIGHT_BRACE</li>
     * </ul>
     * 
     * @return 语句块内的 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private Token nextStatementToken() throws IOException {
        skipWhitespace();

        int ch = source.peek();
        if (ch == -1) {
            throw new TemplateSyntaxException("语句块未闭合", source.getLine(), source.getColumn());
        }

        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        // 检查自闭合语句块结束 %}
        if (ch == '%') {
            int next = source.peek(1);
            if (next == '}') {
                source.read(); // 消费 %
                source.read(); // 消费 }
                mode = Mode.TEXT;
                return new Token(TokenType.STMT_END, "%}", line, column, position);
            }
        }

        // 检查标准语句块开始标签结束 }
        // 注意：标准语句块格式为 {% 语句名称 参数 }，最后的 } 表示开始标签结束
        if (ch == '}') {
            source.read(); // 消费 }
            mode = Mode.TEXT;
            return new Token(TokenType.RIGHT_BRACE, "}", line, column, position);
        }

        // 标识符或关键字
        if (Character.isJavaIdentifierStart(ch)) {
            return readIdentifierOrKeyword();
        }

        // 字符串字面量
        if (ch == '"' || ch == '\'') {
            return readStringLiteral();
        }

        // 数字字面量
        if (Character.isDigit(ch)) {
            return readNumberLiteral();
        }

        // 运算符和分隔符
        return readOperatorOrDelimiter();
    }

    /**
     * 跳过空白字符
     * 
     * <p>在表达式和语句块模式下，空白字符不参与词法分析，需要跳过</p>
     * 
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private void skipWhitespace() throws IOException {
        while (true) {
            int ch = source.peek();
            if (ch == -1 || !Character.isWhitespace(ch)) {
                break;
            }
            source.read();
        }
    }

    /**
     * 读取字符串字面量（单引号或双引号）
     * 
     * <p>支持的转义字符：\n、\t、\r、\\、\'、\"</p>
     * 
     * @return STRING 类型的 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     * @throws TemplateSyntaxException 如果字符串未闭合
     */
    private Token readStringLiteral() throws IOException {
        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        int quote = source.read(); // 消费引号
        StringBuilder value = new StringBuilder();

        while (true) {
            int ch = source.peek();
            if (ch == -1) {
                throw new TemplateSyntaxException("字符串未闭合", line, column);
            }

            if (ch == quote) {
                source.read(); // 消费结束引号
                break;
            }

            if (ch == '\\') {
                source.read(); // 消费 \
                int next = source.peek();
                if (next == -1) {
                    throw new TemplateSyntaxException("字符串未闭合", line, column);
                }
                source.read();
                // 处理转义字符
                switch (next) {
                    case 'n': value.append('\n'); break;
                    case 't': value.append('\t'); break;
                    case 'r': value.append('\r'); break;
                    case '\\': value.append('\\'); break;
                    case '\'': value.append('\''); break;
                    case '"': value.append('"'); break;
                    default: value.append((char) next); break;
                }
            } else {
                value.append((char) source.read());
            }
        }

        return new Token(TokenType.STRING, value.toString(), line, column, position);
    }

    /**
     * 读取字符串模板字面量（反引号包裹）
     * 
     * <p>字符串模板可以包含嵌入的表达式 {...}，例如：`Hello {name}!`</p>
     * 
     * @return TEMPLATE_STRING 类型的 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     * @throws TemplateSyntaxException 如果字符串模板未闭合
     */
    private Token readTemplateLiteral() throws IOException {
        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        source.read(); // 消费 `
        StringBuilder value = new StringBuilder();

        while (true) {
            int ch = source.peek();
            if (ch == -1) {
                throw new TemplateSyntaxException("字符串模板未闭合", line, column);
            }

            if (ch == '`') {
                source.read(); // 消费结束 `
                break;
            }

            value.append((char) source.read());
        }

        return new Token(TokenType.TEMPLATE_STRING, value.toString(), line, column, position);
    }

    /**
     * 读取数字字面量
     * 
     * <p>支持的数字类型：</p>
     * <ul>
     *   <li>整数：123、-456</li>
     *   <li>长整数：123L、-456L</li>
     *   <li>大整数：超出 long 范围的整数自动使用 BigInteger</li>
     *   <li>浮点数：3.14、-0.5</li>
     *   <li>科学计数法：1.23e10、1.5E-8</li>
     *   <li>高精度小数：小数位数超过 10 位时自动使用 BigDecimal</li>
     * </ul>
     * 
     * @return NUMBER、LONG、BIG_INTEGER 或 BIG_DECIMAL 类型的 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private Token readNumberLiteral() throws IOException {
        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        StringBuilder value = new StringBuilder();
        boolean hasDecimalPoint = false;
        boolean hasExponent = false;

        // 处理负号
        if (source.peek() == '-') {
            value.append((char) source.read());
        }

        // 读取数字
        while (true) {
            int ch = source.peek();
            if (ch == -1) {
                break;
            }

            if (Character.isDigit(ch)) {
                value.append((char) source.read());
            } else if (ch == '.' && !hasDecimalPoint && !hasExponent) {
                int next = source.peek(1);
                if (next == '.' || next == '<') {
                    // 这是区间运算符，不是小数点
                    break;
                }
                hasDecimalPoint = true;
                value.append((char) source.read());
            } else if ((ch == 'e' || ch == 'E') && !hasExponent) {
                hasExponent = true;
                hasDecimalPoint = true; // 科学计数法也算浮点数
                value.append((char) source.read());
                int next = source.peek();
                if (next == '+' || next == '-') {
                    value.append((char) source.read());
                }
            } else if (ch == 'L' && !hasDecimalPoint && !hasExponent) {
                source.read(); // 消费 L
                try {
                    Long.parseLong(value.toString());
                    return new Token(TokenType.LONG, value.toString(), line, column, position);
                } catch (NumberFormatException e) {
                    // 超出 long 范围，使用 BigInteger
                    return new Token(TokenType.BIG_INTEGER, value.toString(), line, column, position);
                }
            } else {
                break;
            }
        }

        String numStr = value.toString();

        // 判断数字类型
        if (hasDecimalPoint || hasExponent) {
            // 浮点数
            try {
                Double.parseDouble(numStr);
                // 检查精度，如果精度要求高则使用 BigDecimal
                if (numStr.contains(".") && numStr.substring(numStr.indexOf(".") + 1).length() > 10) {
                    return new Token(TokenType.BIG_DECIMAL, numStr, line, column, position);
                }
                return new Token(TokenType.NUMBER, numStr, line, column, position);
            } catch (NumberFormatException e) {
                return new Token(TokenType.BIG_DECIMAL, numStr, line, column, position);
            }
        } else {
            // 整数
            try {
                Integer.parseInt(numStr);
                return new Token(TokenType.NUMBER, numStr, line, column, position);
            } catch (NumberFormatException e) {
                try {
                    Long.parseLong(numStr);
                    return new Token(TokenType.LONG, numStr, line, column, position);
                } catch (NumberFormatException e2) {
                    return new Token(TokenType.BIG_INTEGER, numStr, line, column, position);
                }
            }
        }
    }

    /**
     * 尝试读取正则表达式字面量
     * 
     * <p>格式：/pattern/ 或 /pattern/flags</p>
     * <p>支持的标志位：g（全局）、i（忽略大小写）、m（多行）</p>
     * <p>注意：需要区分正则表达式和除法运算符 /，通过上下文判断</p>
     * 
     * @return REGEX 类型的 Token，如果不是正则表达式则返回 null
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private Token tryReadRegex() throws IOException {
        source.mark();
        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        try {
            source.read(); // 消费 /
            StringBuilder pattern = new StringBuilder();

            while (true) {
                int ch = source.peek();
                if (ch == -1 || ch == '\n') {
                    source.reset();
                    return null;
                }

                if (ch == '/') {
                    source.read(); // 消费结束 /
                    // 读取标志位
                    StringBuilder flags = new StringBuilder();
                    while (true) {
                        int flag = source.peek();
                        if (flag == 'g' || flag == 'i' || flag == 'm') {
                            flags.append((char) source.read());
                        } else {
                            break;
                        }
                    }
                    String value = pattern.toString() + (flags.length() > 0 ? ":" + flags : "");
                    return new Token(TokenType.REGEX, value, line, column, position);
                }

                if (ch == '\\') {
                    pattern.append((char) source.read());
                    int next = source.peek();
                    if (next != -1) {
                        pattern.append((char) source.read());
                    }
                } else {
                    pattern.append((char) source.read());
                }
            }
        } catch (Exception e) {
            source.reset();
            return null;
        }
    }

    /**
     * 读取标识符或关键字
     * 
     * <p>标识符遵循 Java 命名规则，关键字包括：</p>
     * <ul>
     *   <li>控制流：if、else、for、in、switch、case、default</li>
     *   <li>字面量：true、false、null</li>
     *   <li>嵌入式代码：let、extends、import</li>
     *   <li>运算符：!in</li>
     * </ul>
     * 
     * @return IDENTIFIER 或对应的关键字 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     */
    private Token readIdentifierOrKeyword() throws IOException {
        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        StringBuilder value = new StringBuilder();

        // 第一个字符
        value.append((char) source.read());

        // 后续字符
        while (true) {
            int ch = source.peek();
            if (ch == -1 || !Character.isJavaIdentifierPart(ch)) {
                break;
            }
            value.append((char) source.read());
        }

        String identifier = value.toString();

        // 检查是否是关键字
        Integer keywordType = KEYWORDS.get(identifier);
        if (keywordType != null) {
            return new Token(keywordType, identifier, line, column, position);
        }

        return new Token(TokenType.IDENTIFIER, identifier, line, column, position);
    }

    /**
     * 读取运算符或分隔符
     * 
     * <p>支持的运算符和分隔符：</p>
     * <ul>
     *   <li>分隔符：()、[]、{}、,、;、.</li>
     *   <li>算术运算符：+、-、*、/、%</li>
     *   <li>比较运算符：>、<、>=、<=、==、!=</li>
     *   <li>逻辑运算符：&&、||、!</li>
     *   <li>三元运算符：?、:</li>
     *   <li>赋值运算符：=</li>
     *   <li>空安全操作符：?.</li>
     *   <li>Elvis 运算符：?:</li>
     *   <li>正则匹配：=~、!=~</li>
     *   <li>区间运算符：..、>..<、..<、>..</li>
     *   <li>不包含运算符：!in</li>
     * </ul>
     * 
     * @return 对应的运算符或分隔符 Token
     * @throws IOException 如果读取源代码时发生 I/O 错误
     * @throws TemplateSyntaxException 如果遇到未知字符
     */
    private Token readOperatorOrDelimiter() throws IOException {
        int line = source.getLine();
        int column = source.getColumn();
        int position = source.getPosition();

        int ch = source.read();

        switch (ch) {
            case '(': return new Token(TokenType.LEFT_PAREN, "(", line, column, position);
            case ')': return new Token(TokenType.RIGHT_PAREN, ")", line, column, position);
            case '[': return new Token(TokenType.LEFT_BRACKET, "[", line, column, position);
            case ']': return new Token(TokenType.RIGHT_BRACKET, "]", line, column, position);
            case '{': 
                braceDepth++;
                return new Token(TokenType.LEFT_BRACE, "{", line, column, position);
            case ',': return new Token(TokenType.COMMA, ",", line, column, position);
            case ';': return new Token(TokenType.SEMICOLON, ";", line, column, position);
            case '`': return new Token(TokenType.BACKTICK, "`", line, column, position);

            case '+': return new Token(TokenType.PLUS, "+", line, column, position);
            case '-': return new Token(TokenType.MINUS, "-", line, column, position);
            case '*': return new Token(TokenType.MULTIPLY, "*", line, column, position);
            case '%': return new Token(TokenType.MODULO, "%", line, column, position);

            case '/':
                return new Token(TokenType.DIVIDE, "/", line, column, position);

            case '=':
                if (source.peek() == '=') {
                    source.read();
                    return new Token(TokenType.EQ, "==", line, column, position);
                } else if (source.peek() == '~') {
                    source.read();
                    return new Token(TokenType.REGEX_MATCH, "=~", line, column, position);
                }
                return new Token(TokenType.ASSIGN, "=", line, column, position);

            case '!':
                if (source.peek() == '=') {
                    source.read();
                    if (source.peek() == '~') {
                        source.read();
                        return new Token(TokenType.REGEX_NOT_MATCH, "!=~", line, column, position);
                    }
                    return new Token(TokenType.NEQ, "!=", line, column, position);
                } else if (source.peek() == 'i') {
                    // 检查 !in
                    source.mark();
                    source.read(); // i
                    if (source.peek() == 'n') {
                        source.read(); // n
                        int next = source.peek();
                        if (!Character.isJavaIdentifierPart(next)) {
                            return new Token(TokenType.NOT_IN, "!in", line, column, position);
                        }
                    }
                    source.reset();
                }
                return new Token(TokenType.NOT, "!", line, column, position);

            case '<':
                if (source.peek() == '=') {
                    source.read();
                    return new Token(TokenType.LTE, "<=", line, column, position);
                }
                return new Token(TokenType.LT, "<", line, column, position);

            case '>':
                if (source.peek() == '=') {
                    source.read();
                    return new Token(TokenType.GTE, ">=", line, column, position);
                } else if (source.peek() == '.') {
                    // 区间运算符 >.. 或 >..<
                    source.mark();
                    source.read(); // .
                    if (source.peek() == '.') {
                        source.read(); // .
                        if (source.peek() == '<') {
                            // >..< 全开区间 (a, b)
                            source.read(); // <
                            return new Token(TokenType.RANGE_OPEN, ">..<", line, column, position);
                        }
                        // >.. 前开后闭区间 (a, b]
                        return new Token(TokenType.RANGE_LEFT_OPEN_RIGHT_CLOSED, ">..", line, column, position);
                    }
                    source.reset();
                }
                return new Token(TokenType.GT, ">", line, column, position);

            case '.':
                if (source.peek() == '.') {
                    source.read();
                    if (source.peek() == '<') {
                        // ..< 前闭后开区间 [a, b)
                        source.read();
                        return new Token(TokenType.RANGE_LEFT_CLOSED_RIGHT_OPEN, "..<", line, column, position);
                    }
                    // .. 全闭区间 [a, b]
                    return new Token(TokenType.RANGE_CLOSED, "..", line, column, position);
                }
                return new Token(TokenType.DOT, ".", line, column, position);

            case '&':
                if (source.peek() == '&') {
                    source.read();
                    return new Token(TokenType.AND, "&&", line, column, position);
                }
                throw new TemplateSyntaxException("未知字符: &", line, column);

            case '|':
                if (source.peek() == '|') {
                    source.read();
                    return new Token(TokenType.OR, "||", line, column, position);
                }
                throw new TemplateSyntaxException("未知字符: |", line, column);

            case '?':
                if (source.peek() == '.') {
                    source.read();
                    return new Token(TokenType.SAFE_NAV, "?.", line, column, position);
                } else if (source.peek() == ':') {
                    source.read();
                    return new Token(TokenType.ELVIS, "?:", line, column, position);
                }
                return new Token(TokenType.QUESTION, "?", line, column, position);

            case ':':
                return new Token(TokenType.COLON, ":", line, column, position);

            default:
                throw new TemplateSyntaxException("未知字符: " + (char) ch, line, column);
        }
    }
}

